/*$Id: EclipsePluginMojo.java 48 2010-10-17 18:39:56Z vip.delete $*/

/**
 * Copyright vip_delete
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.eclipseplugin;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.dom.DOMElement;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.*;
import java.util.*;
import java.util.jar.JarInputStream;

/**
 * @author vip_delete
 * @goal eclipse
 * @since 25.07.2010
 */
public class EclipsePluginMojo extends AbstractIDEPluginMojo
{
    /**
     * Path for eclipse workspace
     *
     * @parameter expression="${workspacePath}"
     */
    private String workspacePath;

    /**
     * Path for tomcat or null if no tomcat installation is required
     *
     * @parameter expression="${tomcatPath}"
     */
    private String tomcatPath;

    /**
     * User specific name of the run configuration for the application server
     * If not set, than use name of the war-packaging module
     *
     * @parameter expression="${applicationServerTitle}"
     */
    private String applicationServerTitle;

    /**
     * jreName
     *
     * @parameter expression="${jreName}" default-value="jre6"
     */
    private String jreName;

    /**
     * VM parameters for the web application server
     *
     * @parameter expression="${vmParameters}"
     */
    private String vmParameters;

    /**
     * deployment context of the web application
     *
     * @parameter expression="${deploymentContextPath}" default-value="/"
     */
    private String deploymentContextPath;

    protected void doExecute() throws Exception
    {
        VelocityWorker velocityWorker = getVelocityWorker();
        MavenProject project = getProject();
        List<MavenProject> warProjects = getArtifactHolder().getProjectsWithPackaging("war");
        boolean packagingWar = "war".equals(project.getPackaging());
        boolean packagingPom = "pom".equals(project.getPackaging());
        boolean hasWarProjects = !warProjects.isEmpty();

        VelocityContext context = new VelocityContext();
        context.put("context", this);
        context.put("project", project);
        context.put("packagingWar", packagingWar);
        context.put("packagingPom", packagingPom);
        context.put("outputDirectory", getRelativePath(project.getBuild().getOutputDirectory()));

        if (project.isExecutionRoot())
        {
            if (workspacePath == null)
                throw new MojoFailureException("workspacePath is required!");
            String workspaceFullPath = new File(workspacePath).getCanonicalPath().replace("\\", "/");

            String warArtifact = null;
            String tomcatRuntimeEnvironmentName = null;
            String tomcatName = null;
            String applicationRunConfiguration = null;
            String catalinaSpecificationCode = null;
            String tomcatFullPath = null;

            if (hasWarProjects)
            {
                if (tomcatPath == null)
                    throw new MojoFailureException("tomcatPath is required!");
                warArtifact = warProjects.get(0).getArtifactId();
                tomcatFullPath = hasWarProjects ? new File(tomcatPath).getCanonicalPath().replace("\\", "/") : "";
                applicationRunConfiguration = applicationServerTitle == null ? warArtifact : applicationServerTitle;
                JarInputStream catalinaJar = new JarInputStream(new FileInputStream(new File(tomcatFullPath, "lib/catalina.jar")));
                String catalinaSpecification = catalinaJar.getManifest().getMainAttributes().getValue("Specification-Version");
                catalinaSpecificationCode = catalinaSpecification.replace(".", "");
                catalinaJar.close();
                tomcatRuntimeEnvironmentName = "Apache Tomcat v" + catalinaSpecification;
                tomcatName = tomcatRuntimeEnvironmentName + " Server at localhost-config";
            }

            final byte BEGIN_CHUNK[] = {64, -79, -117, -127, 35, -68, 0, 20, 26, 37, -106, -25, -93, -109, -66, 30};
            final byte END_CHUNK[] = {-64, 88, -5, -13, 35, -68, 0, 20, 26, 81, -13, -116, 123, -69, 119, -58};

            List<MavenProject> reactorProjects = new ArrayList<MavenProject>(getReactorProjects());
            String serversProjectName = "!Servers"; // need to be the first
            Collections.sort(reactorProjects, new Comparator<MavenProject>()
            {
                @Override
                public int compare(MavenProject o1, MavenProject o2)
                {
                    return o1.getArtifact().getArtifactId().compareTo(o2.getArtifactId());
                }
            });

            // create or update eclipse workspace
            File resourcesPlugin = new File(workspaceFullPath, ".metadata/.plugins/org.eclipse.core.resources");
            FileUtils.forceMkdir(resourcesPlugin);

            // make .projects
            {
                File projectsDir = new File(resourcesPlugin, ".projects");
                FileUtils.forceMkdir(projectsDir);
                FileUtils.cleanDirectory(projectsDir);
                if (hasWarProjects)
                {
                    File projectDir = new File(projectsDir, serversProjectName);
                    FileUtils.forceMkdir(projectDir);
                    DataOutputStream output = null;
                    try
                    {
                        output = new DataOutputStream(new FileOutputStream(new File(projectDir, ".location")));
                        output.write(BEGIN_CHUNK);
                        output.writeUTF("URI//file:/" + workspaceFullPath + "/" + serversProjectName);
                        output.writeInt(0);
                        output.write(END_CHUNK);
                    } finally
                    {
                        if (output != null) output.close();
                    }
                }
                for (MavenProject reactorProject : reactorProjects)
                {
                    File projectDir = new File(projectsDir, reactorProject.getArtifactId());
                    FileUtils.forceMkdir(projectDir);
                    DataOutputStream output = null;
                    try
                    {
                        output = new DataOutputStream(new FileOutputStream(new File(projectDir, ".location")));
                        output.write(BEGIN_CHUNK);
                        output.writeUTF("URI//file:/" + reactorProject.getBasedir().getAbsolutePath().replace("\\", "/"));
                        Set<String> dependencies = new TreeSet<String>();
                        for (Artifact artifact : getDependencies(reactorProject))
                            if (isReactorArtifact(artifact))
                                dependencies.add(artifact.getArtifactId());
                        output.writeInt(dependencies.size());
                        for (String artifact : dependencies)
                            output.writeUTF(artifact);
                        output.write(END_CHUNK);
                    } finally
                    {
                        if (output != null) output.close();
                    }
                }
            }

            // make .root
            {
                File rootDir = new File(resourcesPlugin, ".root");
                FileUtils.forceMkdir(rootDir);
                FileUtils.cleanDirectory(rootDir);
                DataOutputStream output = null;
                try
                {
                    output = new DataOutputStream(new FileOutputStream(new File(rootDir, "0.tree")));
                    output.writeInt(0x4030202); // workspace tree version 2
                    output.writeLong(0L); // save the next node id
                    output.writeLong(0L); // save the modification stamp (no longer used)
                    output.writeLong(0L); // save the marker id counter
                    output.writeInt(4);   // save the number registered sync partners in the synchronizer
                    output.writeUTF("org.eclipse.team.cvs.core"); // 1. qualifier
                    output.writeUTF("folder-dirty-state-cached"); // 1. localname
                    output.writeUTF("org.eclipse.team.cvs.core"); // 2. qualifier
                    output.writeUTF("resource-sync");             // 2. localname
                    output.writeUTF("org.eclipse.team.cvs.core"); // 3. qualifier
                    output.writeUTF("folder-sync");               // 3. localname
                    output.writeUTF("org.eclipse.team.cvs");      // 4. qualifier
                    output.writeUTF("remote-resource-key");       // 4. localname
                    output.writeInt(2);   // write the number of plugins we are saving
                    output.writeUTF("org.eclipse.wst.jsdt.core"); // pluginId
                    output.writeUTF("org.eclipse.jdt.core");      // pluginId
                    output.writeInt(reactorProjects.size()); // write the number of builders we are saving
                    for (MavenProject reactorProject : reactorProjects)
                    {
                        output.writeUTF(reactorProject.getArtifactId());     // projectName
                        output.writeUTF("org.eclipse.jdt.core.javabuilder"); // builderName
                        Set<String> dependencies = new TreeSet<String>();
                        for (Artifact artifact : getDependencies(reactorProject))
                            if (isReactorArtifact(artifact))
                                dependencies.add(artifact.getArtifactId());
                        output.writeInt(dependencies.size());      // write the number of interesting projects
                        for (String artifact : dependencies)
                            output.writeUTF(artifact);
                    }
                    output.writeByte(1); // current tree format
                    int treeCount = reactorProjects.size() + 2;
                    output.writeByte(treeCount); // write the number of trees plus some empty trees
                    for (int i = 0; i < treeCount; i++)
                        output.writeByte(treeCount - i - 1); // write the order of each tree (back order)
                    output.writeByte(1); // standard node reader
                    output.writeUTF(""); // empty title for root node
                    output.writeByte(0); // node type is COMPLETE (can has data)
                    output.writeByte(1); // node has some data (but no data for root node lol)
                    output.writeByte((hasWarProjects ? 1 : 0) + reactorProjects.size()); // child count
                    long id = 0;
                    if (hasWarProjects)
                    {
                        output.writeUTF(serversProjectName);
                        output.writeByte(0);      // node type is COMPLETE (can has data)
                        output.writeByte(1);      // node has some data
                        output.writeInt(0x100413);// project in undiscovered folder
                        output.writeLong(0);      // local info
                        output.writeLong(id++);   // unique nodeId
                        output.writeInt(0);       // some modification counter
                        output.writeLong(0);      // some modification stamp
                        output.writeByte(0);      // no child or undiscovered yet
                    }
                    for (MavenProject reactorProject : reactorProjects)
                    {
                        output.writeUTF(reactorProject.getArtifactId()); // first child is project name
                        output.writeByte(0);      // node type is COMPLETE (can has data)
                        output.writeByte(1);      // node has some data
                        output.writeInt(0x100413);// project in undiscovered folder
                        output.writeLong(0);      // local info
                        output.writeLong(id++);   // unique nodeId
                        output.writeInt(0);       // some modification counter
                        output.writeLong(0);      // some modification stamp
                        //id = writeTree(id, output, reactorProject.getBasedir());
                        output.writeByte(0);
                    }
                    for (int i = 0; i < treeCount - 1; i++)
                    {
                        output.writeInt(0x01000003); // empty tree: reader+emptyName+emptyNode
                        output.writeByte(0); // no child
                    }
                } finally
                {
                    if (output != null) output.close();
                }
            }

            // make .safetable
            {
                File safetableDir = new File(resourcesPlugin, ".safetable");
                FileUtils.forceMkdir(safetableDir);
                FileUtils.cleanDirectory(safetableDir);
                DataOutputStream out = null;
                try
                {
                    out = new DataOutputStream(new FileOutputStream(new File(safetableDir, "org.eclipse.core.resources")));
                    out.write(BEGIN_CHUNK);
                    out.write("#master table\n".getBytes());
                    out.write("/.tree=0\n".getBytes());
                    out.write(END_CHUNK);
                    out.write(BEGIN_CHUNK);
                    out.write("#master table\n".getBytes());
                    out.write("/.tree=0\n".getBytes());
                    out.write(END_CHUNK);
                } finally
                {
                    if (out != null) out.close();
                }
            }

            // make runtime settings
            {
                File runtimePlugin = new File(workspaceFullPath, ".metadata/.plugins/org.eclipse.core.runtime/.settings");
                FileUtils.forceMkdir(runtimePlugin);

                // turn off welcome screen
                appendProperties(runtimePlugin, "org.eclipse.ui.prefs",
                        "showIntro", "false"
                );

                // set UTF-8 encoding and turn off autobuilding
                appendProperties(runtimePlugin, "org.eclipse.core.resources.prefs",
                        "encoding", "UTF-8",
                        "description.autobuilding", "false"
                );

                // turn on autosave before build and set workspace name
                appendProperties(runtimePlugin, "org.eclipse.ui.ide.prefs",
                        "SAVE_ALL_BEFORE_BUILD", "true",
                        "WORKSPACE_NAME", project.getName(),
                        "EXIT_PROMPT_ON_CLOSE_LAST_WINDOW", "false",
                        "REFRESH_WORKSPACE_ON_STARTUP", "true"
                );

                // set classpath variable M2_REPO = getLocalRepositoryBasePath()
                appendProperties(runtimePlugin, "org.eclipse.jdt.core.prefs",
                        "org.eclipse.jdt.core.classpathVariable.M2_REPO", getLocalRepositoryBasePath()
                );

                if (hasWarProjects)
                {
                    // add tomcat link
                    appendProperties(runtimePlugin, "org.eclipse.jst.server.tomcat.core.prefs",
                            "locationorg.eclipse.jst.server.tomcat.runtime." + catalinaSpecificationCode, tomcatFullPath
                    );
                    // add server runtime environment with tomcat
                    appendProperties(runtimePlugin, "org.eclipse.wst.server.core.prefs",
                            "runtimes", "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimes>\r\n<runtime id=\"" + tomcatRuntimeEnvironmentName + "\" location=\"" + tomcatFullPath + "\" name=\"Apache Tomcat\" runtime-type-id=\"org.eclipse.jst.server.tomcat.runtime." + catalinaSpecificationCode + "\" timestamp=\"0\"/>\r\n</runtimes>\r\n"
                    );
                }
            }

            // make debug settings
            if (hasWarProjects)
            {
                File debugPlugin = new File(workspaceFullPath, ".metadata/.plugins/org.eclipse.debug.core/.launches");
                FileUtils.forceMkdir(debugPlugin);
                String vmArgs = "-Dcatalina.base=" + workspaceFullPath + "/.metadata/.plugins/org.eclipse.wst.server.core/tmp0\n" +
                        "-Dcatalina.home=" + tomcatFullPath + "\n" +
                        "-Dwtp.deploy=" + workspaceFullPath + "/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps\n" +
                        "-Djava.endorsed.dirs=" + tomcatFullPath + "/endorsed";
                if (vmParameters != null)
                    vmArgs = vmParameters + "\n" + vmArgs;

                writeStringIntoFile(new File(debugPlugin, applicationRunConfiguration + ".launch"), "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
                        "<launchConfiguration type=\"org.eclipse.jst.server.tomcat.core.launchConfigurationType\">\n" +
                        "  <listAttribute key=\"org.eclipse.debug.ui.favoriteGroups\">\n" +
                        "    <listEntry value=\"org.eclipse.debug.ui.launchGroup.debug\"/>\n" +
                        "  </listAttribute>\n" +
                        "  <listAttribute key=\"org.eclipse.jdt.launching.CLASSPATH\">\n" +
                        "    <listEntry value=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/" + jreName + "&quot; path=&quot;2&quot; type=&quot;4&quot;/&gt;\"/>\n" +
                        "    <listEntry value=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;" + tomcatFullPath + "/bin/bootstrap.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;\"/>\n" +
                        "    <listEntry value=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;" + tomcatFullPath + "/bin/tomcat-juli.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;\"/>\n" +
                        "  </listAttribute>\n" +
                        "  <booleanAttribute key=\"org.eclipse.jdt.launching.DEFAULT_CLASSPATH\" value=\"false\"/>\n" +
                        "  <stringAttribute key=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/" + jreName + "\" value=\"org.eclipse.jdt.launching.JRE_CONTAINER\"/>\n" +
                        "  <stringAttribute key=\"org.eclipse.jdt.launching.PROGRAM_ARGUMENTS\" value=\"start\"/>\n" +
                        "  <stringAttribute key=\"org.eclipse.jdt.launching.VM_ARGUMENTS\" value=\"" + XMLUtil.escapeXmlAttribute(vmArgs) + "\"/>\n" +
                        "  <stringAttribute key=\"server-id\" value=\"" + tomcatName + "\"/>\n" +
                        "</launchConfiguration>"
                );

                File debugUiPlugin = new File(workspaceFullPath, ".metadata/.plugins/org.eclipse.debug.ui");
                FileUtils.forceMkdir(debugUiPlugin);
                writeStringIntoFile(new File(debugUiPlugin, "launchConfigurationHistory.xml"), "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
                        "<launchHistory>\n" +
                        "<launchGroup id=\"org.eclipse.ui.externaltools.launchGroup\">\n" +
                        "<mruHistory/>\n" +
                        "<favorites/>\n" +
                        "</launchGroup>\n" +
                        "<launchGroup id=\"org.eclipse.debug.ui.launchGroup.profile\">\n" +
                        "<mruHistory>\n" +
                        "<launch memento=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;launchConfiguration local=&quot;true&quot; path=&quot;" + applicationRunConfiguration + "&quot;/&gt;&#13;&#10;\"/>\n" +
                        "</mruHistory>\n" +
                        "<favorites/>\n" +
                        "</launchGroup>\n" +
                        "<launchGroup id=\"org.eclipse.debug.ui.launchGroup.debug\">\n" +
                        "<mruHistory>\n" +
                        "<launch memento=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;launchConfiguration local=&quot;true&quot; path=&quot;" + applicationRunConfiguration + "&quot;/&gt;&#13;&#10;\"/>\n" +
                        "</mruHistory>\n" +
                        "<favorites>\n" +
                        "<launch memento=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;launchConfiguration local=&quot;true&quot; path=&quot;" + applicationRunConfiguration + "&quot;/&gt;&#13;&#10;\"/>\n" +
                        "</favorites>\n" +
                        "</launchGroup>\n" +
                        "<launchGroup id=\"org.eclipse.debug.ui.launchGroup.run\">\n" +
                        "<mruHistory>\n" +
                        "<launch memento=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;launchConfiguration local=&quot;true&quot; path=&quot;" + applicationRunConfiguration + "&quot;/&gt;&#13;&#10;\"/>\n" +
                        "</mruHistory>\n" +
                        "<favorites/>\n" +
                        "</launchGroup>\n" +
                        "</launchHistory>"
                );
            }

            // add server project to workspace
            if (hasWarProjects)
            {
                // add tomcat plugin configuration
                File serverPlugin = new File(workspaceFullPath, ".metadata/.plugins/org.eclipse.wst.server.core");
                FileUtils.forceMkdir(serverPlugin);
                writeStringIntoFile(new File(serverPlugin, "servers.xml"), "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
                        "<servers>\n" +
                        "  <server auto-publish-setting=\"2\" auto-publish-time=\"1\" configuration-id=\"/" + serversProjectName + "/" + tomcatName + "\" deployDir=\"wtpwebapps\" hostname=\"localhost\" id=\"" + tomcatName + "\" name=\"" + tomcatName + "\" runtime-id=\"" + tomcatRuntimeEnvironmentName + "\" server-type=\"org.eclipse.jst.server.tomcat." + catalinaSpecificationCode + "\" server-type-id=\"org.eclipse.jst.server.tomcat." + catalinaSpecificationCode + "\" start-timeout=\"45\" stop-timeout=\"15\" testEnvironment=\"true\" timestamp=\"3\">\n" +
                        "    <list key=\"modules\" value0=\"" + warArtifact + "::org.eclipse.jst.j2ee.server:" + warArtifact + "::jst.web::2.4\"/>\n" +
                        "  </server>\n" +
                        "</servers>");

                // add tomcat project
                File serversProject = new File(workspaceFullPath, serversProjectName);
                FileUtils.forceMkdir(serversProject);
                File tomcatConfig = new File(serversProject, tomcatName);
                FileUtils.forceMkdir(tomcatConfig);
                FileUtils.copyFileToDirectory(new File(tomcatFullPath, "conf/catalina.policy"), tomcatConfig);
                FileUtils.copyFileToDirectory(new File(tomcatFullPath, "conf/catalina.properties"), tomcatConfig);
                FileUtils.copyFileToDirectory(new File(tomcatFullPath, "conf/context.xml"), tomcatConfig);
                FileUtils.copyFileToDirectory(new File(tomcatFullPath, "conf/server.xml"), tomcatConfig);
                FileUtils.copyFileToDirectory(new File(tomcatFullPath, "conf/tomcat-users.xml"), tomcatConfig);
                FileUtils.copyFileToDirectory(new File(tomcatFullPath, "conf/web.xml"), tomcatConfig);
                Document document = new SAXReader().read(new File(tomcatConfig, "server.xml"));
                Element hostElement = document.getRootElement().element("Service").element("Engine").element("Host");
                DOMElement contextElement = new DOMElement("Context");
                contextElement.setAttribute("docBase", warArtifact);
                contextElement.setAttribute("path", "/");
                contextElement.setAttribute("reloadable", "true");
                contextElement.setAttribute("source", "org.eclipse.jst.j2ee.server:" + warArtifact);
                hostElement.add(contextElement);
                XMLWriter xmlWriter = null;
                try
                {
                    xmlWriter = new XMLWriter(new FileOutputStream(new File(tomcatConfig, "server.xml")));
                    xmlWriter.write(document);
                    xmlWriter.close();
                } finally
                {
                    if (xmlWriter != null) xmlWriter.close();
                }

                writeStringIntoFile(new File(serversProject, ".project"),
                        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                                "<projectDescription>" +
                                "<name>Servers</name>" +
                                "<comment></comment>" +
                                "<projects></projects>" +
                                "<buildSpec></buildSpec>" +
                                "<natures></natures>" +
                                "</projectDescription>");
                File serversSettings = new File(serversProject, ".settings");
                FileUtils.forceMkdir(serversSettings);
                writeStringIntoFile(new File(serversSettings, "org.eclipse.wst.server.core.prefs"),
                        "org.eclipse.wst.server.core.isServerProject=true"
                );
            }
        }

        FileUtils.forceDelete(new File(project.getBasedir(), ".project"));
        createFile(project.getBasedir(), context, velocityWorker.getProjectTemplate(), ".project");

        FileUtils.forceDelete(new File(project.getBasedir(), ".classpath"));
        createFile(project.getBasedir(), context, velocityWorker.getClasspathTemplate(), ".classpath");

        // make web-facet
        if (!packagingPom && hasWarProjects)
        {
            File settings = new File(project.getBasedir(), ".settings");
            FileUtils.forceMkdir(settings);
            context.put("deploymentContextPath", deploymentContextPath);

            FileUtils.forceDelete(new File(settings, "org.eclipse.wst.common.component"));
            createFile(settings, context, velocityWorker.getModulesTemplate(), "org.eclipse.wst.common.component");

            if (packagingWar)
            {
                writeStringIntoFile(new File(settings, "org.eclipse.wst.common.project.facet.core.xml"), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                        "<faceted-project>\n" +
                        "  <runtime name=\"Apache Tomcat\"/>\n" +
                        "  <installed facet=\"jst.java\" version=\"6.0\"/>\n" +
                        "  <installed facet=\"jst.web\" version=\"2.4\"/>\n" +
                        "</faceted-project>");
            } else
            {
                writeStringIntoFile(new File(settings, "org.eclipse.wst.common.project.facet.core.xml"), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                        "<faceted-project>\n" +
                        "  <fixed facet=\"java\"/>\n" +
                        "  <fixed facet=\"jst.utility\"/>\n" +
                        "  <installed facet=\"java\" version=\"1.6\"/>\n" +
                        "  <installed facet=\"jst.utility\" version=\"1.0\"/>\n" +
                        "</faceted-project>");
            }
        }
    }

    private void appendProperties(File baseDir, String fileName, String... nameAndValues) throws Exception
    {
        File prefs = new File(baseDir, fileName);
        Properties properties = new Properties();
        if (prefs.exists())
            properties.load(new FileInputStream(prefs));
        for (int i = 0; i < nameAndValues.length; i += 2)
            properties.put(nameAndValues[i], nameAndValues[i + 1]);
        FileOutputStream outputStream = null;
        try
        {
            outputStream = new FileOutputStream(prefs);
            properties.store(outputStream, null);
        } finally
        {
            if (outputStream != null) outputStream.close();
        }
    }

    private void writeStringIntoFile(File file, String string) throws Exception
    {
        FileOutputStream output = null;
        try
        {
            output = new FileOutputStream(file);
            IOUtil.copy(string, output);
        } finally
        {
            if (output != null) output.close();
        }
    }

    private void createFile(File baseDir, VelocityContext context, Template template, String name) throws Exception
    {
        File file = new File(baseDir, name);
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
        template.merge(context, writer);
        writer.close();
    }

    public boolean isExistsPath(String fullPath)
    {
        return new File(fullPath).exists();
    }

    public String getRelativePath(String fullPath)
    {
        String absolutePath = new File(fullPath).getAbsolutePath();
        String projectPath = getProject().getBasedir().getAbsolutePath() + File.separatorChar;
        if (!absolutePath.startsWith(projectPath))
            throw new RuntimeException("Path '" + absolutePath + "' have to be inside the project '" + getProject().getId() + "'");
        return absolutePath.substring(projectPath.length());
    }

    private long writeTree(long id, DataOutputStream output, File file) throws Exception
    {
        if (file.isFile())
        {
            output.writeByte(0);
        } else
        {
            File[] childs = file.listFiles();
            int size = childs.length;
            for (File child : childs) if (child.getName().startsWith(".")) size--;
            output.writeByte(size);    // child count
            for (File child : childs)
            {
                if (child.getName().startsWith(".")) continue;
                output.writeUTF(child.getName()); // first child is project name
                output.writeByte(0);    // node type is COMPLETE (can has data)
                output.writeByte(1);    // node has some data
                //if (deep == 0)
                //    output.writeInt(child.isDirectory() ? 0x100202 : 0x040102);
                //else
                output.writeInt(child.isDirectory() ? 0x0202 : 0x040102);
                output.writeLong(0);    // node is not sync yet
                output.writeLong(id++); // unique nodeId
                output.writeInt(0);     // some modification counter
                output.writeLong(0);    // some modification stamp
                //if (deep == 0)
                //    output.writeByte(0);   // no child
                //else
                id = writeTree(id, output, child);
            }
        }
        return id;
    }
}

